package containerlogistik.implementation;

import static containerlogistik.implementation.Values.*;
import containerlogistik.interfaces.Acceleration;
import containerlogistik.interfaces.Length;
import containerlogistik.interfaces.Speed;
import containerlogistik.interfaces.TimeDiff;

public class SpeedInMS extends AbstractValue<Speed> implements Speed {
    
    private double meterPerSecond;
    
    private SpeedInMS(double meterPerSec) {
        this.meterPerSecond = meterPerSec;
    }
    
    static Speed valueOf(double meterPerSec) {
        return new SpeedInMS(meterPerSec);
    }

    @Override
    public double ms() {
        return this.meterPerSecond;
    }

    @Override
    public double kmh() {
        return this.ms() * KMH_IN_MS;
    }

    @Override
    public double mph() {
        return this.ms() * MHP_IN_MS;
    }

    @Override
    public boolean isZero() {
        return (this.equals(ZERO_SPEED));
    }
    
    @Override
    public boolean isZero(double delta) {
        double min = ZERO_SPEED.ms() - delta;
        double max = ZERO_SPEED.ms() + delta;
        return (this.ms() >= min && this.ms() <= max);
    }

    @Override
    public boolean isValid() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public String toString() {
        return "SpeedInMS{" + "ms=" + this.ms() + ", kmh=" + this.kmh() + 
                ", mph=" + this.mph() + '}';
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final SpeedInMS other = (SpeedInMS) obj;
        if (Double.doubleToLongBits(this.ms()) != Double.doubleToLongBits(other.ms())) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        return hashDouble(this.ms());
    }

    @Override
    public int compareTo(Speed o) {
        return Double.compare(this.ms(), o.ms());
    }

    @Override
    public Speed add(Speed value) {
        return speedInMS(this.ms() + value.ms());
    }

    @Override
    public Speed sub(Speed value) {
        return speedInMS(this.ms() - value.ms());
    }

    @Override
    public Speed mul(double factor) {
        return speedInMS(this.ms() * factor);
    }

    @Override
    public Speed div(double factor) {
        return speedInMS(this.ms() * factor);
    }

    @Override
    public Speed inverse() {
        return speedInMS(-this.ms());
    }

    @Override
    public double div(Speed value) {
        return (this.ms() / value.ms());
    }

    @Override
    public Length mul(TimeDiff time) {
        return lengthInM(this.ms() * time.s());
    }
    
    public static Speed maxInCurve(Acceleration acc, Length radius) {
        return speedInMS(Math.sqrt(acc.mul(radius.m()).ms2()));
    }
}